﻿
package extremefx.i18n {

	/**
	 * @author Marcelo Volmaro
	 */
	internal class CCHebrew {
		private static const EPOCH:int = -1373427;
		
		public static function _isLeapYear(pYear:int):Boolean {
			return CCMath.mod(7*pYear+1, 19) < 7; 
		}
		
		public static function _lastMonthOfYear(pYear:int):int {
			return _isLeapYear(pYear) ? 13 : 12;
		}
		
		private static function _elapsedDays(pYear:int):int {
			var monthsElapsed:int = CCMath.div(235*pYear-234, 19);
			
			var remainder:Array = [];
			var d:int = CCMath.divMod(remainder, monthsElapsed, 1080);
			 
			var partsElapsed:int = 204 + 793 * int(remainder[0]);
			var hoursElapsed:int = 11 + 12 * monthsElapsed + 793 * d + CCMath.div(partsElapsed, 1080);
			var day:int = 29*monthsElapsed + CCMath.div(hoursElapsed, 24);
	
			if (CCMath.mod(3*(day+1), 7) < 3) {
				day += 1;
			}
	
			return day;
		}
		
		private static function _newYearDelay(pYear:int):int {
			var ny1:int = _elapsedDays(pYear);
			var ny2:int = _elapsedDays(pYear+1);
	
			if (ny2 - ny1 == 356) {
				return 2;
			}
			
			var ny0:int = _elapsedDays(pYear-1);
			if (ny1 - ny0 == 382) {
				return 1;
			}
			return 0;
		}
		
		public static function _lastDayOfMonth(pMonth:int, pYear:int):int {
			if (pMonth < 1 || pMonth > 13) throw new RangeError("pMonth", "Month should be between One and Thirteen.");
				
			switch (pMonth) {
				case 2: return 29;
				case 4: return 29;
				case 6: return 29;
				case 8:
					if (!_longHeshvan(pYear)) return 29;
					break;
					
				case 9:
					if (_shortKislev(pYear)) return 29;
					break;
					
				case 10: return 29;
				case 12:
					if (!_isLeapYear(pYear)) return 29;
					break;
					
				case 13: return 29;
			}
			
			return 30;
		}
		
		private static function _longHeshvan(pYear:int):Boolean {
			return CCMath.mod(_daysInYear(pYear), 10) == 5;
		}
		
		private static function _shortKislev(pYear:int):Boolean {
			return CCMath.mod(_daysInYear(pYear), 10) == 3;
		}
		
		private static function _daysInYear(pYear:int):int {
			return	_fixedFromDMY(1, 7, pYear + 1) - _fixedFromDMY(1, 7, pYear);
		}
		
		public static function _fixedFromDMY(pDay:int, pMonth:int, pYear:int):int {
			var m:int;
			var k:int = EPOCH - 1;
			k += _elapsedDays(pYear);
			k += _newYearDelay(pYear);
	
			if (pMonth < 7) {
				var l:int = _lastMonthOfYear(pYear);
				
				for (m = 7; m <= l; m++) {
					k += _lastDayOfMonth(m, pYear);
				}
				
				for (m = 1; m < pMonth; m++) {
					k += _lastDayOfMonth(m, pYear);
				}
			}
			else {
				for (m = 7; m < pMonth; m++) {
					k += _lastDayOfMonth(m, pYear);
				}
			}

			return k + pDay;
		}
		
		public static function _yearFromFixed(pDate:int):int {
			var approx:int = int(Math.floor( Number(pDate - EPOCH) / (35975351/98496) ));
			var y:int;
			for (y = approx; pDate >= _fixedFromDMY(1, 7, y); y++) {} 
			return y - 1;
		}
		
		public static function _myFromFixed(pDate:int):Array {
			var year:int = _yearFromFixed(pDate);
			var start:int = pDate < _fixedFromDMY(1, 1, year) ? 7 : 1;
			var month:int;
			
			for (month = start; pDate > _fixedFromDMY(_lastDayOfMonth(month, year),	month, year); month++) {}
			
			return [year, month];
		}
		
		public static function _dmyFromFixed(pDate:int):Array {
			var a:Array = _myFromFixed(pDate);
			a.push(pDate - _fixedFromDMY(1, int(a[1]), int(a[0])) + 1);
			return a;
		}
		
//		private static function _monthFromFixed(pDate:int):int {
//			return int(_myFromFixed(pDate)[1]);
//		}
		
		public static function _dayFromFixed(pDate:int):int {
			return int(_dmyFromFixed(pDate)[2]);
		}
		
//		private static function _dateDifference(pDayA:int, pMonthA:int, pYearA:int, pDayB:int, pMonthB:int, pYearB:int):int {
//			return	_fixedFromDMY(pDayB, pMonthB, pYearB) - _fixedFromDMY(pDayA, pMonthA, pYearA);
//		}
		
//		private static function _dayNumber(pDay:int, pMonth:int, pYear:int):int {
//			return _dateDifference(1, 7, pYear, pDay, pMonth, pYear) + 1;
//		}
//		
//		private static function _daysRemaining(pDay:int, pMonth:int, pYear:int):int {
//			return _dateDifference(pDay, pMonth, pYear, 1, 7, pYear+1)-1;
//		}
	}
}
